package cn.zifangsky.utils;

import cn.zifangsky.license.LicenseCreator;
import cn.zifangsky.model.LicenseCheckModel;
import cn.zifangsky.model.LicenseCreatorParam;
import org.springframework.core.io.ClassPathResource;

import java.io.*;
import java.security.KeyStore;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.util.*;

/**
 * 生成密钥对
 * @Author guoyb
 * @Date 2023/10/24  15:35
 */
public class BuildKeyUtils {

    /**
     * 生成密钥对
     * */
    public static void buildKeyAndSaveToJksFile() throws IOException {
        //	相当于在cmd输入以下命令
        //	keytool -genkeypair -storetype PKCS12 -alias test -keyalg EC -groupname secp521r1 -sigalg SHA256withECDSA -dname "CN=Hivesplace,OU=oAuth2.0 Authorization Server,O=123.com,L=Guangzhou,S=Guangdong,C=CN" -keystore ./src/main/resources/keys-and-certs/raviSSL.keystore -keypass 123456789 -storepass 123456789 -validity 36500 -v
        String[] command = new String[] {
                //[避坑] 必须用/c（不要用/k），否则连续执行functions没效果
                "cmd","/C",
                "keytool -genkeypair -storetype PKCS12 -alias raviSSL -keyalg EC -keysize 521 -sigalg SHA256withECDSA -dname \"CN=Hivesplace,OU=oAuth2.0 Authorization Server,O=123.com,L=Guangzhou,S=Guangdong,C=CN\" -keystore ./src/main/resources/keys-and-certs/raviSSL.keystore -keypass 123456789 -storepass 123456789 -validity 365 -v"
        };
        executeCommand(command);
    }

    /**
     * java执行命令
     * @param command
     * @throws IOException
     */
    public static void executeCommand (String[] command) throws IOException {
        Runtime.getRuntime().exec(command);
    }





    /**
     * 导出证书、公钥、私钥
     * */
    public static void exportKeysAndCertsFromKeyStore() throws Exception {
        //以 PKCS12 规格，创建 KeyStore
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        //载入 jks 和该 jks 的密码 到 KeyStore 内
        keyStore.load(new FileInputStream(new ClassPathResource("keys-and-certs/raviSSL.keystore").getFile()), "123456789".toCharArray());

        // 要获取 key，需要提供 KeyStore 的别名 和该 KeyStore 的密码
        // 获取 keyStore 内所有别名 alias
        Enumeration<String> aliases = keyStore.aliases();
        String alias = null;

        //文档写入格式换行+Base64
        final String LINE_SEPARATOR = System.getProperty("line.separator");
        final Base64.Encoder encoder = Base64.getMimeEncoder(64, LINE_SEPARATOR.getBytes());

        while (aliases.hasMoreElements()) {
            alias = aliases.nextElement();
            System.out.println("jks文件别名是："+ alias);
            char[] keyPassword = "123456789".toCharArray();

            System.out.println("jks文件中的私钥是：\nkey format: "+keyStore.getKey(alias, keyPassword).getFormat()+"\n"+"-----BEGIN PRIVATE KEY-----"+LINE_SEPARATOR+new String(encoder.encode(keyStore.getKey(alias, keyPassword).getEncoded()))+LINE_SEPARATOR+"-----END PRIVATE KEY-----"+"\n");
            String keyContent = "-----BEGIN PRIVATE KEY-----"+LINE_SEPARATOR+new String(encoder.encode(keyStore.getKey(alias, keyPassword).getEncoded()))+LINE_SEPARATOR+"-----END PRIVATE KEY-----";
            //			命名方法： alias.key
            writeKeyOrCertToFile("./src/main/resources/keys-and-certs/"+alias+".key", keyContent);
            ;

            Certificate certificate = keyStore.getCertificate(alias);

            System.out.println("jks文件中的证书是：\ncertificate format: "+certificate.getType()+"\n"+"-----BEGIN CERTIFICATE-----"+LINE_SEPARATOR+new String(encoder.encode(certificate.getEncoded()))+LINE_SEPARATOR+"-----END CERTIFICATE-----");
            String certificateContent = "-----BEGIN CERTIFICATE-----"+LINE_SEPARATOR+new String(encoder.encode(certificate.getEncoded()))+LINE_SEPARATOR+"-----END CERTIFICATE-----";
            //			命名方法： alias.cer
            writeKeyOrCertToFile("./src/main/resources/keys-and-certs/"+alias+".cer", certificateContent);

            PublicKey publicKey = certificate.getPublicKey();
            System.out.println("jks文件中的公钥是：\npublic key format: "+publicKey.getFormat()+"\n"+"-----BEGIN PUBLIC KEY-----"+LINE_SEPARATOR+new String(encoder.encode(publicKey.getEncoded()))+LINE_SEPARATOR+"-----END PUBLIC KEY-----");
            String cerContent = "-----BEGIN PUBLIC KEY-----"+LINE_SEPARATOR+new String(encoder.encode(publicKey.getEncoded()))+LINE_SEPARATOR+"-----END PUBLIC KEY-----";
            //			命名方法： alias.pub
            writeKeyOrCertToFile("./src/main/resources/keys-and-certs/"+alias+".pub", cerContent);
        }
    }

    /**
     *创建文档流
     * */
    public static void writeKeyOrCertToFile(String filePathAndName, String fileContent) throws IOException {
        //		FileOutputStream ：是字节流，它一个字节一个字节的向外边送数据 该类用来创建一个文件并向文件中写数据。
        //		OutputStreamWriter：是字符流，它一个字符一个字符的向外边送数据
        //		因为中文是一个字符，至少占俩字节。
        //		如果只用stream，读出来的中文会乱码；如果用WRITER，就不会有乱码
        //
        //		BufferedWriter建立了一个缓冲区，
        //		如果直接用stream或者writer，你的硬盘可能就是读一个字符或者一个字节 就去读写硬盘一次，IO负担巨大
        //		可是用了Buffer，你的硬盘就是读了一堆数据之后，读写一下硬盘。这样对硬盘有好处
        //
        // 注意：用这三个类新建文件，如果没有文件则会重新创建文件，如果有，则仍然用之前的文件，
        FileOutputStream fos = new FileOutputStream(filePathAndName);
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        BufferedWriter bw = new BufferedWriter(osw);
        bw.write(fileContent);
        bw.close();
    }


    public static void main(String[] args) {
        LicenseCreatorParam param=new LicenseCreatorParam();
        param.setSubject("license_demo");
        param.setPrivateAlias("privateKey");
        param.setKeyPass("private_password1234");
        param.setStorePass("public_password1234");
        param.setLicensePath("C:\\Users\\Joker_DJ\\Desktop\\license_demo\\license.lic");
        param.setPrivateKeysStorePath("C:\\Users\\Joker_DJ\\Desktop\\license_demo\\privateKeys.keystore");
        param.setIssuedTime(new Date());
        param.setExpiryTime(new Date(Date.parse("4/6/2024")));
        param.setConsumerType("User");
        param.setConsumerAmount(1);
        param.setDescription("这是证书描述信息");
        LicenseCheckModel licenseCheckModel = new LicenseCheckModel();
        List<String> ipAddress=new ArrayList<>();
        List<String> macAddress=new ArrayList<>();
        //  ipAddress.add("192.168.3.5");
        licenseCheckModel.setIpAddress(ipAddress);
        macAddress.add("2C-F0-5D-B0-FB-6D");
        licenseCheckModel.setMacAddress(macAddress);
        licenseCheckModel.setCpuSerial("BFEBFBFF000A0653");
        licenseCheckModel.setMainBoardSerial("K9G0031056");
        param.setLicenseCheckModel(licenseCheckModel);
        LicenseCreator licenseCreator = new LicenseCreator(param);
        boolean result = licenseCreator.generateLicense();
        System.out.println(result);
    }
}
